#include <iostream>
#include <string>

#include "Array_t.h"
#include "Dlist_t.h"


int main(int argc, char* argv[])
{

	// Example Main

	bool cont	= true;
	unsigned int c;
	int val=1;
	int index = -2;

	if(1){
		Container_t<int> *test;
		int type = 2;
		std::cout<<"Please type \"1\" for Array_t or \"2\" for Dlist_t:"<<std::endl;
		std::cin >> type;

		if(type==1)
		{
			test = new Array_t<int>;
			std::cout<<"Now using Array_t"<<std::endl;
		}
		else if(type==2)
		{
			test = new Dlist_t<int>;
			std::cout<<"Now using Dlist_t"<<std::endl;
		}
		else
		{
			test = new Dlist_t<int>;
			std::cout<<"Default: using Dlist_t"<<std::endl;
		}

		while (cont) {
			std::cout << "	0: insert" 	<< std::endl
				<< "	1: append" 	<< std::endl
				<< "	2: prepend" 	<< std::endl
				<< "	3: find" 	<< std::endl
				<< "	4: remove" 	<< std::endl
				<< "	5: removeAll" 	<< std::endl
				<< "	6: removeAndDelete"	<< std::endl
				<< "	7: removeAndDeleteAll"	<< std::endl
				<< "	8: print" <<std::endl
				<< "	-1: exit"	<< std::endl
				<< "Enter your choice : ";
			std::cin >> c;

			switch (c) {
			case 0:
				std::cout<<"insert: type in value (integer):"<<std::endl;
				std::cin >> val;
				test->insert(new int(val));	
				break;
			case 1:
				std::cout<<"append: type in value (integer):"<<std::endl;
				std::cin >> val;
				std::cout<<"append: insert index for append:"<<std::endl;
				std::cin >> index;
				try{
					test->append(new int(val), index);
				}
				catch(const char* e)
				{
					std::cout<<"append fail: "<<e<<std::endl;
				}
				break;
			case 2:
				std::cout<<"prepend: type in value (integer):"<<std::endl;
				std::cin >> val;
				std::cout<<"prepend: insert index for prepend:"<<std::endl;
				std::cin >> index;
				try{
					test->prepend(new int(val), index);
				}
				catch(const char* e)
				{
					std::cout<<"prepend fail: "<<e<<std::endl;
				}
				break;
			case 3:
				std::cout<<"find: type in value (integer):"<<std::endl;
				std::cin >> val;
				std::cout<< (test->find(val)?"Found!":"Not Found")<<std::endl;
				break;
			case 4:
				std::cout<<"removed: type in value (integer):"<<std::endl;
				std::cin >> val;
				test->remove(val);
				break;
			case 5:
				std::cout<<"removedAll............";
				test->removeAll();
				std::cout<<"Done!"<<std::endl;
				break;
			case 6:
				std::cout<<"removedAndDelete: type in value (integer):"<<std::endl;
				std::cin >> val;
				test->removeAndDelete(val);
				break;
			case 7:
				std::cout<<"removedAndDeleteAll:...........";
				test->removeAndDeleteAll();
				std::cout<<"Done!"<<std::endl;
				break;
			case 8:
				test->print();
				break;
			case -1:
				test->removeAndDeleteAll();
				cont=false;
				break;
			default : cont = false;
			}
		}
		delete test;

		return 0;
	} //if

	/////////////////// Dlist tests ////////////////////
	Dlist_t<float> list1;

	bool res = false;
	float* temp = NULL;

	float* p1 = new float; *p1 = (float)9.011;
	float* p2 = new float; *p2 = (float)7.70321;
	float* p3 = new float; *p3 = (float)3;
	float* p4 = new float; *p4 = (float)3;
	float* p5 = new float; *p5 = (float)1.1;
	float* f10 = new float; *f10 = (float)10.10;
	float* f12 = new float; *f12 = (float)12.12;
	float* f14 = new float; *f14 = (float)14.14;

	list1.insert(p1);
	list1.insert(p2);
	list1.insert(p3);
	temp = list1.find(3); // should pass
	temp = list1.remove(3); // should pass
	res = list1.removeAndDelete((float)3); // should do nothing
	if(res!=false)
		std::cout<<"res = false, you should not see this!"<<std::endl;
	list1.insert(p5);
	res = list1.removeAndDelete((float)7.70321); // deletes p2

	// TODO: remove!!!
	list1.print();

	try 
	{
		list1.append(p3, -2); // This should fail
	}
	catch(const char* e)
	{
		std::cout<<"list1.append(p3, -2) Fail: "<<e<<std::endl;
	}

	// TODO: remove!!!
	list1.print();

	list1.append(p3, 0); // This should succeed

	// TODO: remove!!!
	list1.print();

	try
	{ //this one should FAIL
		list1.prepend(f10,-1);
	}
	catch(const char* e)
	{
		std::cout<<"list1.prepend(f10,-1) Fail: "<<e<<std::endl;
	}

	try
	{ //this one should FAIL
		list1.append(f10,3);
	}
	catch(const char* e)
	{
		std::cout<<"list1.append(f10,3) Fail: "<<e<<std::endl;
	}

	for(size_t i = 0; i < list1.count(); i++)
	{
		temp = list1.next();
	}
	list1.reset();

	for(size_t i = 0; i < list1.count(); i++)
	{
		temp = list1.next();
	}
	list1.reset();

	// TODO: remove!!!
	list1.print();

	try
	{
		Dlist_t<float> list2 = list1;

		// TODO: remove!!!
		list2.print();
	}
	catch(const char* e)
	{
		std::cout<<"Error: "<<e<<std::endl;
	}

	try
	{
		Dlist_t<float> list2;
		list2 = list1;

		// TODO: remove!!!
		list2.print();
	}
	catch(const char* e)
	{
		std::cout<<"Error: "<<e<<std::endl;
	}

	Dlist_t<float> list10 = list1;
	list1.removeAll(); // this should not affect list 10

	////////////////////////// container tests /////////////////
	Container_t<float> *c2 = new Dlist_t<float>;
	*c2 = list10;
	std::cout<<"list10:"<<std::endl;
	list10.print();
	std::cout<<"c2:"<<std::endl;
	c2->print();
	delete c2;

	// TODO: remove!!!
	list1.print();
	list10.print();
	list10.removeAll();
	list10.append(p5,-1); list10.prepend(f10,0); list10.insert(f14); list10.prepend(f12,0);
	list10.print();

	// Deletions
	delete p1;
	delete p3;
	delete p4;
	delete p5;
	delete f10;
	delete f12;
	delete f14;

	////////////// Array tests ///////////////////

	Array_t<int> a1;
	int *i1=new int; *i1=1;
	int *i2=new int; *i2=2;
	int *i3=new int; *i3=3;
	int *i4=new int; *i4=4;
	int *i5=new int; *i5=5;
	int *i6=new int; *i6=6;
	int *i7=new int; *i7=7;
	int *i8=new int; *i8=8;
	int *i9=new int; *i9=9;

	a1.append(i1,-1);
	a1.append(i2,-1);
	a1.append(i3,-1);
	a1.append(i4,-1);
	a1.insert(i5);

	Array_t<int> a2 = a1;

	a1.remove(2);

	Array_t<int> a3 = a1;

	try //this one should FAIL
	{
		a3.append(i6,-2);
	}
	catch(const char* e)
	{
		std::cout<<"Error: "<<e<<std::endl;
	}

	try //this one should FAIL
	{
		a3.prepend(i6,-2);
	}
	catch(const char* e)
	{
		std::cout<<"Error: "<<e<<std::endl;
	}

	try //this one should FAIL
	{
		a2.prepend(i6,6);
	}
	catch(const char* e)
	{
		std::cout<<"Error: "<<e<<std::endl;
	}

	try //this one should PASS
	{
		a2.append(i7,4);
	}
	catch(const char* e)
	{
		std::cout<<"You shouldn't see this"<<e<<std::endl;
	}

	a3.prepend(i7,0);

	// this one should return NULL
	int *j = NULL;
	j=a3.find(8);
	if(j==NULL)
		std::cout<<"You SHOULD see this"<<std::endl;

	j=a3.find(4);
	if(j!=NULL)
		std::cout<<"You SHOULD also see this"<<std::endl;

	// operator=
	Array_t<int> a4;
	a4 = a2;

	// should not affect a4
	a2.removeAll();

	std::cout<<"a1:"<<std::endl;
	a1.print();
	std::cout<<"a2:"<<std::endl;
	a2.print();
	std::cout<<"a3:"<<std::endl;
	for(int i=0; i<5; i++)
		std::cout<<"a3["<<i<<"]="<<a3[i]<<std::endl; //operator[]
	std::cout<<"a4:"<<std::endl;
	a4.print();

	a2.insert(i1);
	a2.insert(i2);
	a2.insert(i3);
	a2.insert(i4);
	a2.insert(i5);
	a2.insert(i6);
	a2.insert(i7);
	a2.insert(i8);
	a2.insert(i9);

	std::cout<<"a2:"<<std::endl;
	a2.print();


	////////////////////////// container tests /////////////////
	Container_t<int> *c1 = new Array_t<int>;
	*c1 = a3;
	std::cout<<"Printing Container:"<<std::endl;
	c1->print();


	getchar();
	delete i1; delete i2; delete i3; delete i4; delete i5; delete i6; delete i7; delete i8; delete i9;
	delete c1;
	return 0;
}